package com.lsa.skienna.challenge.chap9.the110904_SlashMaze;

import java.io.InputStream;
import java.io.PrintStream;
import java.util.Scanner;
import java.util.Stack;

public class Main {
	static final int MAXV = 30000;
	static boolean processed[] = new boolean[MAXV];
	static boolean discovered[] = new boolean[MAXV];
	static int parent[] = new int[MAXV];
	static boolean finished = false;
	static int entry_time[] = new int[MAXV];
	static int exit_time[] = new int[MAXV];
	
	static int cyclesNum = 0;
	static int mazeNumber = 0;
	static int longestCycleLength = 0;
	static InputStream in;
	static PrintStream out;
	
	public static void main(String[] args) {
		process(System.in, out);
	}
	
	public static void process(InputStream in, PrintStream out) {
		Main.in = in;
		Main.out = out;
		graph g = null;
		mazeNumber = 0;
		Scanner sc = new Scanner(in);
		while( (g = readMazeGraph(sc)) != null) {
			initialize_search(g);
			findCycles(g);
			reportCycles();
		}
	}
	
	static graph readMazeGraph(Scanner sc) {
		int w = sc.nextInt();
		int h = sc.nextInt();
		
		if (w == 0 && h == 0) {
			return null;
		}
		
		graph g = new graph();
		if (w == 0 || h == 0) {
			return g;
		}
		
		g.nvertices = w*h*4;
		
		for (int j = 1; j <= h; j++) {
			String line = sc.next("[\\\\/]+");
			for (int i = 1; i <= w; i++) {
				String token = line.substring(i - 1, i);
				int lowestNodeNumber = numberingFunction(i, j, w);
				if ("\\".equals(token)) {
					g.insert_edge(lowestNodeNumber, lowestNodeNumber + 2, false);
					g.insert_edge(lowestNodeNumber + 1, lowestNodeNumber + 3, false);
				}
				else if ("/".equals(token)) {
					g.insert_edge(lowestNodeNumber, lowestNodeNumber + 1, false);
					g.insert_edge(lowestNodeNumber + 2, lowestNodeNumber + 3, false);
				}
				else {
					throw new RuntimeException(String.format("unexpected token [%s]",token)); 
				}
				
				if (i > 1) {
					int leftNeighbourLowestNodeNumber = numberingFunction(i - 1, j, w);
					g.insert_edge(leftNeighbourLowestNodeNumber + 2, lowestNodeNumber + 1, false);
				}
				if (j > 1) {
					int upperNeighbourLowestNodeNumber = numberingFunction(i , j - 1, w);
					g.insert_edge(upperNeighbourLowestNodeNumber + 3, lowestNodeNumber, false);
				}
			}
		}
		return g;
	}
	
	static int numberingFunction(int i, int j, int w) {
		return 4 * i + 4 * w * j - 4 * w - 3;
	}
	
	static void findCycles(graph g) {
		for (int u = 1; u <= g.nvertices; ++u) {
			if (!processed[u]) {
				dfsNoRecursion(g, u);
			}
		}
	}
	
	static void reportCycles() {
		out.print(String.format("Maze #%s:\n", mazeNumber));
		if (cyclesNum > 0) {
			out.print(String.format("%s Cycles; the longest has length %s.\n", cyclesNum, longestCycleLength / 2));
		}
		else {
			out.print("There are no cycles.\n");
		}
		out.print("\n");
	}
	
	static int cycleLength(int start, int end, int parents[]) {
		if (start == end ) {
			return 1;
		}
		int length = 0;
		
		int u = end;
		do {
			u = parents[u];
			++length;
		}while(u != start);
		
		return length;
	}
	
	static boolean valid_edge(int v)
	{
		return true;
	}
	
	static void process_vertex_early(int v)
	{
		timer++;
		entry_time[v] = timer;
	}
	
	static void process_vertex_late(int v)
	{
		timer++;
		exit_time[v] = timer;
	}
	
	static final int TREE = 1;
	static final int BACK = 2;
	static final int FORWARD = 3;
	static final int CROSS = 4;
	static int timer = 0;
	
	static int edge_classification(int x, int y)
	{
		if (parent[y] == x) return(TREE);
		if (discovered[y] && !processed[y]) return(BACK);
		if (processed[y] && (entry_time[y]>entry_time[x])) return(FORWARD);
		if (processed[y] && (entry_time[y]<entry_time[x])) return(CROSS);
		return -1;
	}

	static void dfsNoRecursion(graph g, int v) {
		Stack<Integer> stack = new Stack<Integer>();
		stack.push(v);

start:			
		while (!stack.isEmpty()) {
			int y;
			if (finished)
				return;
			
			v = stack.pop();
			
			discovered[v] = true;
			timer++;
			entry_time[v] = timer;
			process_vertex_early(v);
			
			for (int i = g.degree[v] - 1; i >= 0; i--) {
				y = g.edges[v][i];
				if (!discovered[y]) {
					parent[y] = v;
					process_edge(v, y);
					stack.push(y);
					continue start;
				} else {
					if (!processed[y])
						process_edge(v, y);
				}
				if (finished)
					return;
			}
			process_vertex_late(v);
			timer++;
			exit_time[v] = timer;
			processed[v] = true;
		}
	}
		
	static void process_edge(int x,int y)
	{
		int c = edge_classification(x,y);
		if (c != TREE) { // cycle
			int length = find_path_length(y, x, parent);
			if (length > 1) {
//				System.out.println(y + " " + x );
				length = length + 1; 
//				out.println("cycle length : "+length);
				cyclesNum++;
				if (longestCycleLength < length) {
					longestCycleLength = length;
				}
			}
		}
	}
	
	
	static void initialize_search(graph g)
	{
		mazeNumber++;
		cyclesNum = 0;
		longestCycleLength = 0;
		for(int i=0;i<=g.nvertices;i++)
		{
			processed[i] = discovered[i] = false;
			parent[i] = -1;
		}
	}
	
	static void process_vertex(int v)
	{
	}
	
	static int find_path_length(int start, int end, int parents[])
	{
		if(start==end || end == -1) {
//			out.printf("\n %d", start);
			return 0;
		}
		else
		{
			try{
				return find_path_length(start, parents[end], parents) + 1;
			}
			finally{
//				out.printf(" %d ", end);
			}
		}
	}

	static class queue {
		public final int QUEUESIZE = 1000;
		int q[];
		int first;
		int last;
		int count;
		queue()
		{
			q = new int [QUEUESIZE + 1];
			first = 0;
			last = QUEUESIZE - 1;
			count = 0;
		}
		void enqueue(int x)
		{
			if(count >= QUEUESIZE)
				out.printf("Warning: queue overflow enqueue x = %d\n", x);
			else
			{
				last = (last + 1) % QUEUESIZE;
				q[last] = x;
				count++;
			}
		}
		int dequeue()
		{
			int x;
			if(count <= 0)
			{
				out.printf("Warning: empty queue dequeue.\n");
				return -1;
			}
			else
			{
				x = q[first];
				first = (first + 1) % QUEUESIZE;
				count--;
				return x;
			}
		}
		boolean empty()
		{
			if(count <= 0)
				return true;
			else
				return false;
		}
		
		void show_queue()
		{
			for(int i=first,cnt=0;cnt<=count;i=(i+1)%QUEUESIZE,cnt++)
				out.printf("%d ",q[i]);
			out.printf("\n");
		}
	}

	static  class graph
	{
		static final int MAXDEGREE = 50;
		
		public int edges[][] = new int [MAXV+1][MAXDEGREE];
		public int degree[] = new int [MAXV+1];
		public int nvertices;
		public int nedges;
		
		graph()
		{
			nvertices = nedges = 0;
			for(int i=1;i<=MAXV;i++)
				degree[i] = 0;
		}
		
		void read_graph(boolean directed)
		{
			int x,y;
			Scanner sc = new Scanner(System.in);
			nvertices = sc.nextInt();
			int m = sc.nextInt();
			for(int i=1;i<=m;i++)
			{
				x=sc.nextInt();
				y=sc.nextInt();
				insert_edge(x,y,directed);
			}
		}
		
		void insert_edge(int x, int y, boolean directed)
		{
			if(degree[x]>MAXDEGREE)
				out.printf("Warning: insertion (%d, %d) exceeds max degree\n",x,y);
			edges[x][degree[x]] = y;
			degree[x]++;
			if(!directed)
				insert_edge(y,x,true);
			else
				nedges++;
		}
		
		void print_graph()
		{
			for(int i=1;i<=nvertices;i++)
			{
				out.printf("%d: ",i);
				for(int j=degree[i]-1;j>=0;j--)
					out.printf(" %d",edges[i][j]);
				out.printf("\n");
			}
		}
	}
}
